package com.jctrip.hotel.source.service.meituan.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.jctrip.hotel.common.constant.RedisKeyConstant;
import com.jctrip.hotel.common.constant.XxlJobNameConstant;
import com.jctrip.hotel.common.threadpool.XxlJobThreadPool;
import com.jctrip.hotel.common.util.JsonUtil;
import com.jctrip.hotel.common.util.RedisUtil;
import com.jctrip.hotel.domain.dao.HtHotelMthdomInfoDao;
import com.jctrip.hotel.domain.dao.HtRoomtypeMthdomInfoDao;
import com.jctrip.hotel.domain.entity.HtHotelMthdomInfo;
import com.jctrip.hotel.domain.entity.HtRoomtypeMthdomInfo;
import com.jctrip.hotel.source.model.meituan.req.ContentReq;
import com.jctrip.hotel.source.model.meituan.req.PoiListReq;
import com.jctrip.hotel.source.model.meituan.req.RealroomContentReq;
import com.jctrip.hotel.source.model.meituan.resp.ContentResp;
import com.jctrip.hotel.source.model.meituan.resp.PoiListResp;
import com.jctrip.hotel.source.model.meituan.resp.RealroomContentResp;
import com.jctrip.hotel.source.service.basic.HtHotelMthdomInfoService;
import com.jctrip.hotel.source.service.basic.HtRoomtypeMthdomInfoService;
import com.jctrip.hotel.source.service.meituan.MeituanService;
import com.jctrip.hotel.source.service.meituan.MeituanTaskService;
import com.jctrip.hotel.source.xxl.meituan.thread.SyncHotelStaticInfoTaskThread;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

/**
 * @Author: zxy
 * @CreateTime: 2024-01-05 11:13
 * @Description:
 */
@Service
@Slf4j
public class MeituanTaskServiceImpl implements MeituanTaskService {
    private static final long PUSH_EXPIRY = 1 * 60;
    private static final XxlJobThreadPool hotelIdListTaskPool =
            new XxlJobThreadPool(XxlJobNameConstant.SYNC_MTHDOM_HOTEL_ID_LIST_TASK_POP);

    @Resource
    RedisUtil redisUtil;
    @Autowired
    private MeituanService meituanService;
    @Autowired
    private HtHotelMthdomInfoService htHotelMthdomInfoService;
    @Autowired
    private HtRoomtypeMthdomInfoService htRoomtypeMthdomInfoService;

    @Override
    public void syncHotelStaticInfoPush(Integer partnerId, String accessKey, String secretKey, PoiListReq req) {
        try {
            if (redisUtil.setENx(RedisKeyConstant.HOTEL_MAIN_MEITUAN_STATIC_INFO_PUSH, PUSH_EXPIRY,
                    RedisKeyConstant.HOTEL_MAIN_MEITUAN_STATIC_INFO_PUSH)) {
                List<Long> hotelIds = new ArrayList<>();
                while (true) {
                    PoiListResp poiListResp = meituanService.poiListMeituan(req, partnerId, accessKey, secretKey);
                    if (null == poiListResp || poiListResp.getMaxId() == -1
                            || CollectionUtils.isEmpty(poiListResp.getHotelIds())) {
                        break;
                    }
                    hotelIds.addAll(poiListResp.getHotelIds());
                    req.setMaxId(poiListResp.getMaxId());
                }

                if (CollectionUtils.isNotEmpty(hotelIds)
                        && redisUtil.lGetListSize(RedisKeyConstant.HOTEL_MAIN_MEITUAN_HOTELId_LIST) <= 0) {
                    redisUtil.leftPushAll(RedisKeyConstant.HOTEL_MAIN_MEITUAN_HOTELId_LIST,
                            new ArrayList<>(hotelIds));
                }
            }
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }
    }

    @Override
    public void syncHotelStaticInfoPop(Integer partnerId, String accessKey, String secretKey) {
        hotelIdListTaskPool.execute(() -> new SyncHotelStaticInfoTaskThread(accessKey, secretKey, partnerId));
    }

    @Override
    public void syncHotelStaticInfo(Integer partnerId, String accessKey, String secretKey, String hotelId) {
        try {
            List<Long> hotelIds = new ArrayList<>();
            hotelIds.add(Long.parseLong(meituanService.parseHotelId(hotelId)));
            List<String> include = new ArrayList<>();
            include.add("HotelContent.baseInfo");
            include.add("HotelContent.detailInfo");
            include.add("HotelContent.notices");
            include.add("HotelContent.policy");
            include.add("HotelContent.facilities");
            include.add("HotelContent.images");
            include.add("HotelContent.roomBaseInfos");
            ContentReq contentReq = ContentReq.builder()
                    .hotelIds(hotelIds)
                    .include(include)
                    .build();
            ContentResp contentResp = meituanService.contentMeituan(contentReq, partnerId, accessKey, secretKey);
            HtHotelMthdomInfo htHotelMthdomInfo = setHtHotelMthdomInfo(contentResp);
            if (StringUtils.isBlank(htHotelMthdomInfo.getHotelId())) {
                log.error("hotelId {} is null", hotelId);
                return;
            }
            htHotelMthdomInfoService.saveOrUpdate(htHotelMthdomInfo, new LambdaQueryWrapper<HtHotelMthdomInfo>()
                    .eq(HtHotelMthdomInfo::getHotelId, htHotelMthdomInfo.getHotelId()));
            RealroomContentResp realroomContentResp =
                    meituanService.realroomContentMeituan(
                            RealroomContentReq.builder()
                                    .hotelId(Long.parseLong(meituanService.parseHotelId(hotelId)))
                                    .build()
                            , partnerId, accessKey, secretKey);
            realroomContentResp.getRoomContents().forEach(e -> {
                if (Objects.nonNull(e.getBaseInfo())
                        && Objects.nonNull(e.getBaseInfo().getRealRoomId())) {
                    HtRoomtypeMthdomInfo htRoomtypeMthdomInfo = setHtRoomtypeMthdomInfo(e);
                    if (StringUtils.isBlank(htRoomtypeMthdomInfo.getRoomTypeCode())) {
                        return;
                    }
                    htRoomtypeMthdomInfoService.saveOrUpdate(htRoomtypeMthdomInfo,
                            new LambdaQueryWrapper<HtRoomtypeMthdomInfo>()
                                    .eq(HtRoomtypeMthdomInfo::getHotelId, htRoomtypeMthdomInfo.getHotelId())
                                    .eq(HtRoomtypeMthdomInfo::getRoomTypeCode, htRoomtypeMthdomInfo.getRoomTypeCode()));
                }
            });
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }

    }

    private HtHotelMthdomInfo setHtHotelMthdomInfo(ContentResp contentResp) {
        HtHotelMthdomInfo htHotelMthdomInfo = new HtHotelMthdomInfo();
        contentResp.getHotelContents().forEach(e -> {
            htHotelMthdomInfo.setHotelId(meituanService.parseInnId(String.valueOf(e.getHotelId())));
            ContentResp.BaseInfo baseInfo = e.getBaseInfo();
            ContentResp.DetailInfo detailInfo = e.getDetailInfo();
            if (Objects.isNull(baseInfo) || Objects.isNull(detailInfo)) {
                return;
            }

            htHotelMthdomInfo.setHotelName(baseInfo.getName());
            htHotelMthdomInfo.setHotelNameEn(baseInfo.getNameEn());

            ContentResp.Group group = detailInfo.getGroup();
            htHotelMthdomInfo.setGroupCode(Objects.nonNull(group) ? group.getCode() : null);
            htHotelMthdomInfo.setGroupName(Objects.nonNull(group) ? group.getName() : null);


            ContentResp.Brand brand = detailInfo.getBrand();
            htHotelMthdomInfo.setBrandCode(Objects.nonNull(brand) ? brand.getCode() : null);
            htHotelMthdomInfo.setBrandName(Objects.nonNull(brand) ? brand.getName() : null);

            ContentResp.Address address = baseInfo.getAddress();
            if (Objects.isNull(address)) {
                return;
            }

            ContentResp.AddressLine addressLine = address.getAddressLine();
            htHotelMthdomInfo.setHotelAddress(Objects.nonNull(addressLine) ? addressLine.getName() : null);
            htHotelMthdomInfo.setHotelAddressEn(Objects.nonNull(addressLine) ? addressLine.getNameEn() : null);
            htHotelMthdomInfo.setHotelTel(baseInfo.getPhone());

            ContentResp.Country country = address.getCountry();
            htHotelMthdomInfo.setCountryCode(Objects.nonNull(country) ? String.valueOf(country.getCode()) : null);
            htHotelMthdomInfo.setCountryName(Objects.nonNull(country) ? country.getName() : null);

            ContentResp.Province province = address.getProvince();
            htHotelMthdomInfo.setProvinceCode(Objects.nonNull(province) ? String.valueOf(province.getCode()) : null);
            htHotelMthdomInfo.setProvinceName(Objects.nonNull(province) ? province.getName() : null);

            ContentResp.City city = address.getCity();
            htHotelMthdomInfo.setCityCode(Objects.nonNull(city) ? String.valueOf(city.getCode()) : null);
            htHotelMthdomInfo.setCityName(Objects.nonNull(city) ? city.getName() : null);

            ContentResp.Area area = address.getArea();
            htHotelMthdomInfo.setDistrictCode(Objects.nonNull(area) ? String.valueOf(area.getCode()) : null);
            htHotelMthdomInfo.setDistrictName(Objects.nonNull(area) ? area.getName() : null);
            htHotelMthdomInfo.setIntroduction(detailInfo.getDescription());
            htHotelMthdomInfo.setSourceStatus(baseInfo.getBookable() ? 1 : 0);
            htHotelMthdomInfo.setOverseas(Objects.nonNull(country) && country.getCode() == 10000001 ? 0 : 1);

            ContentResp.Policy policy = e.getPolicy();
            if (Objects.isNull(policy)) {
                return;
            }
            ContentResp.GuestPolicy guestPolicy = policy.getGuestPolicy();
            ContentResp.BreakfastPolicy breakfastPolicy = policy.getBreakfastPolicy();
            htHotelMthdomInfo.setSupportForeignGuest(Objects.nonNull(guestPolicy) && Objects.nonNull(guestPolicy.getGuestType()) ?
                    guestPolicy.getGuestType().getCode() : null);
            htHotelMthdomInfo.setSupportRestaurant(Objects.nonNull(breakfastPolicy) ? breakfastPolicy.getHasBreakfast() : null);
            List<ContentResp.Coordinate> coordinates = address.getCoordinates();
            htHotelMthdomInfo.setLongitude(CollectionUtils.isNotEmpty(coordinates) ? coordinates.get(0).getLongitude().longValue() : null);
            htHotelMthdomInfo.setLatitude(CollectionUtils.isNotEmpty(coordinates) ? coordinates.get(0).getLatitude().longValue() : null);
            if (CollectionUtils.isNotEmpty(coordinates)) {
                String provider = coordinates.get(0).getProvider();
                switch (provider) {
                    case "GAODE":
                        htHotelMthdomInfo.setMapPointType(3);
                        break;
                    case "BAIDU":
                        htHotelMthdomInfo.setMapPointType(0);
                        break;
                    case "MAPBAR":
                        htHotelMthdomInfo.setMapPointType(4);
                        break;
                    case "GOOGLE":
                        htHotelMthdomInfo.setMapPointType(1);
                        break;
                    default:
                        htHotelMthdomInfo.setMapPointType(null);
                        break;
                }
            } else {
                htHotelMthdomInfo.setMapPointType(null);
            }
        });
        return htHotelMthdomInfo;
    }

    private HtRoomtypeMthdomInfo setHtRoomtypeMthdomInfo(RealroomContentResp.RoomContent roomContent) {
        HtRoomtypeMthdomInfo htRoomtypeMthdomInfo = new HtRoomtypeMthdomInfo();
        ContentResp.RoomBaseInfo baseInfo = roomContent.getBaseInfo();

        htRoomtypeMthdomInfo.setHotelId(meituanService.parseInnId(String.valueOf(baseInfo.getHotelId())));
        htRoomtypeMthdomInfo.setRoomTypeCode(String.valueOf(baseInfo.getRealRoomId()));
        htRoomtypeMthdomInfo.setRoomTypeName(baseInfo.getName());
        htRoomtypeMthdomInfo.setRoomArea(baseInfo.getUseAbleArea());
        htRoomtypeMthdomInfo.setRoomStatus(baseInfo.getStatus());
        htRoomtypeMthdomInfo.setFloor(baseInfo.getFloor());
        htRoomtypeMthdomInfo.setMaxCheckIn(Objects.nonNull(baseInfo.getOccupancy()) ?
                baseInfo.getOccupancy().getTotal() : null);

        List<List<ContentResp.BedGroup>> bedGroups = baseInfo.getBedGroups();
        if (CollectionUtils.isEmpty(bedGroups) || CollectionUtils.isEmpty(bedGroups.get(0))) {
            htRoomtypeMthdomInfo.setBedType(null);
            htRoomtypeMthdomInfo.setBedWidth(null);
        } else {
            List<ContentResp.BedGroup> bedGroupList = bedGroups.get(0);
            if (Objects.isNull(bedGroupList.get(0))) {
                htRoomtypeMthdomInfo.setBedType(null);
                htRoomtypeMthdomInfo.setBedWidth(null);
            } else if (bedGroupList.get(0).getCount() == 2) {
                htRoomtypeMthdomInfo.setBedType(2);
            } else {
                switch (roomContent.getBaseInfo().getBedGroups().get(0).get(0).getType()) {
                    case "大床":
                        htRoomtypeMthdomInfo.setBedType(0);
                        break;
                    case "单人床":
                        htRoomtypeMthdomInfo.setBedType(1);
                        break;
                    case "双人床":
                        htRoomtypeMthdomInfo.setBedType(4);
                        break;
                    case "特大床":
                        htRoomtypeMthdomInfo.setBedType(3);
                        break;
                    default:
                        htRoomtypeMthdomInfo.setBedType(5);
                        break;
                }
                htRoomtypeMthdomInfo.setBedWidth(bedGroupList.get(0).getDescription());
            }
        }

        htRoomtypeMthdomInfo.setAddBed(baseInfo.getAllowExtraBed() ? 1 : 0);

        if (baseInfo.getWindow() == null) {
            htRoomtypeMthdomInfo.setWindowType(null);
            htRoomtypeMthdomInfo.setWindowTypeDefect(null);
        } else {
            ContentResp.Window window = baseInfo.getWindow();
            switch (window.getHasWindow()) {
                case 0:
                    htRoomtypeMthdomInfo.setWindowType(1);
                    break;
                case 1:
                    htRoomtypeMthdomInfo.setWindowType(2);
                    break;
                case 2:
                    htRoomtypeMthdomInfo.setWindowType(0);
                    break;
                default:
                    break;
            }
            htRoomtypeMthdomInfo.setWindowTypeDefect(window.getDisadvantage());
        }

        return htRoomtypeMthdomInfo;
    }
}
